Last modification: 20 May, 2020

@EricJCGalvez

The data re-analized in this section has been previoulsy published in :

De Filippis, F., Pasolli, E., Tett, A., Tarallo, S., Naccarati, A., De Angelis, M., Neviani, E., Cocolin, L., Gobbetti, M., Segata, N., et al. (2019). Distinct Genetic and Functional Traits of Human Intestinal Prevotella copri Strains Are Associated with Different Habitual Diets. Cell Host Microbe 25, 444-453.e3.

  library("data.table")
  library("maptools")
## Loading required package: sp
## Checking rgeos availability: TRUE
  library("ggalt")
## Loading required package: ggplot2
## Registered S3 methods overwritten by 'ggalt':
##   method                  from   
##   grid.draw.absoluteGrob  ggplot2
##   grobHeight.absoluteGrob ggplot2
##   grobWidth.absoluteGrob  ggplot2
##   grobX.absoluteGrob      ggplot2
##   grobY.absoluteGrob      ggplot2
  library("ggthemes")
  library("tibble")
  library("viridis")
## Loading required package: viridisLite
  library("maps")
  library("phyloseq")
  library("here")
## here() starts at /Users/ega13/MBP001/galvez_et_al_2020:/pMAGs_PULs_in_DeFilippis_et_al_2019_fig5/diversity_analysis
  library("MIKIbiomeR")

Data Load

## Processing phylogenetic tree...
##  ../data/tree.nwk ...
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:data.table':
## 
##     between, first, last
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
## # A tibble: 4 x 2
##   Location  Freq
##   <chr>    <int>
## 1 Bari        16
## 2 Bologna      5
## 3 Parma       18
## 4 Torino      62
## # A tibble: 3 x 2
##   Diet        Freq
##   <chr>      <int>
## 1 Omnivore      25
## 2 Vegan         37
## 3 Vegetarian    39

Italy map

##  [1] "Bolzano-Bozen"   "Belluno"         "Udine"           "Sondrio"        
##  [5] "Trento"          "Novara"          "Pordenone"       "Brescia"        
##  [9] "Como"            "Varese"          "Treviso"         "Bergamo"        
## [13] "Gorizia"         "Vicenza"         "Aosta"           "Vercelli"       
## [17] "Venezia"         "Verona"          "Trieste"         "Milano"         
## [21] "Padova"          "Torino"          "Cremona"         "Mantova"        
## [25] "Pavia"           "Alessandria"     "Rovigo"          "Piacenza"       
## [29] "Asti"            "Parma"           "Reggio Emilia"   "Ferrara"        
## [33] "Modena"          "Cuneo"           "Bologna"         "Genova"         
## [37] "Ravenna"         "Savona"          "Massa-Carrara"   "La Spezia"      
## [41] "Forli'"          "Lucca"           "Firenze"         "Pistoia"        
## [45] "Imperia"         "Pesaro e Urbino" "Arezzo"          "Pisa"           
## [49] "Ancona"          "Livorno"         "Perugia"         "Siena"          
## [53] "Macerata"        "Ascoli Piceno"   "Grosseto"        "Terni"          
## [57] "Teramo"          "Viterbo"         "Rieti"           "L'Aquila"       
## [61] "Pescara"         "Chieti"          "Roma"            "Campobasso"     
## [65] "Foggia"          "Frosinone"       "Isernia"         "Latina"         
## [69] "Caserta"         "Benevento"       "Bari"            "Avellino"       
## [73] "Sassari"         "Potenza"         "Napoli"          "Brindisi"       
## [77] "Nuoro"           "Salerno"         "Matera"          "Taranto"        
## [81] "Lecce"           "Oristano"        "Cosenza"         "Cagliari"       
## [85] "Catanzaro"       "Messina"         "Palermo"         "Reggio Calabria"
## [89] "Trapani"         "Catania"         "Enna"            "Caltanissetta"  
## [93] "Agrigento"       "Siracusa"        "Ragusa"
## Warning: Ignoring unknown aesthetics: x, y

Prepare metagenomic data outputs from ATLAS to phyloseq

Create phyloseq object

alpha diversity by Diet

## You set `rngseed` to FALSE. Make sure you've set & recorded
##  the random seed of your session for reproducibility.
## See `?set.seed`
## ...
## 378OTUs were removed because they are no longer 
## present in any sample after random subsampling
## ...
## [[1]]
## 
## [[2]]
## 
## [[3]]
## 
## [[4]]

PCoA and NMDS composition by Diet and Location

## Warning: Ignoring unknown parameters: stat
## Square root transformation
## Wisconsin double standardization
## Run 0 stress 0.1861141 
## Run 1 stress 0.1874194 
## Run 2 stress 0.1905015 
## Run 3 stress 0.186121 
## ... Procrustes: rmse 0.0008622721  max resid 0.008051025 
## ... Similar to previous best
## Run 4 stress 0.2296703 
## Run 5 stress 0.1907465 
## Run 6 stress 0.1893578 
## Run 7 stress 0.1861221 
## ... Procrustes: rmse 0.001215341  max resid 0.01138018 
## Run 8 stress 0.1907561 
## Run 9 stress 0.1861139 
## ... New best solution
## ... Procrustes: rmse 6.843207e-05  max resid 0.0003773191 
## ... Similar to previous best
## Run 10 stress 0.1907561 
## Run 11 stress 0.1861138 
## ... New best solution
## ... Procrustes: rmse 3.961961e-05  max resid 0.0003182569 
## ... Similar to previous best
## Run 12 stress 0.1893224 
## Run 13 stress 0.1861138 
## ... New best solution
## ... Procrustes: rmse 1.328881e-05  max resid 7.664712e-05 
## ... Similar to previous best
## Run 14 stress 0.2012147 
## Run 15 stress 0.1893223 
## Run 16 stress 0.1861139 
## ... Procrustes: rmse 4.762174e-05  max resid 0.000386171 
## ... Similar to previous best
## Run 17 stress 0.1874194 
## Run 18 stress 0.2328294 
## Run 19 stress 0.1861139 
## ... Procrustes: rmse 3.594775e-05  max resid 0.0002984794 
## ... Similar to previous best
## Run 20 stress 0.1861202 
## ... Procrustes: rmse 0.0008399812  max resid 0.007852233 
## ... Similar to previous best
## *** Solution reached
## Warning: Removed 1 rows containing missing values (position_stack).

## Square root transformation
## Wisconsin double standardization
## Run 0 stress 0.1861141 
## Run 1 stress 0.1874196 
## Run 2 stress 0.1893583 
## Run 3 stress 0.2022387 
## Run 4 stress 0.1874194 
## Run 5 stress 0.1893221 
## Run 6 stress 0.1861138 
## ... New best solution
## ... Procrustes: rmse 5.122147e-05  max resid 0.0002759518 
## ... Similar to previous best
## Run 7 stress 0.1861138 
## ... New best solution
## ... Procrustes: rmse 1.401117e-05  max resid 9.493521e-05 
## ... Similar to previous best
## Run 8 stress 0.2384704 
## Run 9 stress 0.1907465 
## Run 10 stress 0.2022387 
## Run 11 stress 0.1907466 
## Run 12 stress 0.239634 
## Run 13 stress 0.1897001 
## Run 14 stress 0.201219 
## Run 15 stress 0.1907465 
## Run 16 stress 0.2396903 
## Run 17 stress 0.1907466 
## Run 18 stress 0.1874194 
## Run 19 stress 0.1874195 
## Run 20 stress 0.1861222 
## ... Procrustes: rmse 0.001253227  max resid 0.01173818 
## *** Solution reached

Barplot (absolute coverage), facet by Diet

Barplot relative abundance (%), facet by Diet

Abundance of Prevotellaceae MAGs by diet

Total recontructed MAGs 34

P. copri MAGs:

PULs diagram

## 
## Attaching package: 'purrr'
## The following object is masked from 'package:maps':
## 
##     map
## The following object is masked from 'package:data.table':
## 
##     transpose
## Warning: Expected 2 pieces. Additional pieces discarded in 20 rows [3, 51, 112,
## 231, 408, 422, 424, 566, 736, 799, 1233, 1353, 1354, 1458, 1524, 1525, 1567,
## 1577, 1657, 1698].
## Warning: Expected 2 pieces. Missing pieces filled with `NA` in 1600 rows [1, 2,
## 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, ...].
##       genome pulid   protein_id            contig start   end strand  dist
##    1: MAG571  PUL1 MAG571_00776 gnl|HZI|MAG571_18 12184 13941      -     0
##    2: MAG571  PUL1 MAG571_00777 gnl|HZI|MAG571_18 13975 17061      -    34
##    3: MAG571  PUL2 MAG571_01512 gnl|HZI|MAG571_57  7242  8213      - -9819
##    4: MAG571  PUL2 MAG571_01513 gnl|HZI|MAG571_57  8228  8758      -    15
##    5: MAG571  PUL2 MAG571_01514 gnl|HZI|MAG571_57  9024 10748      -   266
##   ---                                                                     
## 1727: MAG655  PUL2 MAG655_01344 gnl|HZI|MAG655_20 21604 22305      +    31
## 1728: MAG655  PUL2 MAG655_01345 gnl|HZI|MAG655_20 22329 22865      +    24
## 1729: MAG655  PUL2 MAG655_01346 gnl|HZI|MAG655_20 23066 24622      +   201
## 1730: MAG655  PUL2 MAG655_01347 gnl|HZI|MAG655_20 24977 26401      +   355
## 1731: MAG655  PUL2 MAG655_01348 gnl|HZI|MAG655_20 26444 29755      +    43
##       protein_name    sus                 hmm Cazy_Fam sub_fam active direction
##    1: MAG571_00776   susD                                 <NA>     NA        -1
##    2: MAG571_00777 susC_1                                 <NA>     NA        -1
##    3: MAG571_01512    GT2 GT2_Glycos_transf_2      GT2  Glycos     NA        -1
##    4: MAG571_01513    unk                                 <NA>     NA        -1
##    5: MAG571_01514   susD                                 <NA>     NA        -1
##   ---                                                                          
## 1727: MAG655_01344    unk                                 <NA>     NA         1
## 1728: MAG655_01345    unk                                 <NA>     NA         1
## 1729: MAG655_01346    PL9               PL9_2      PL9       2     NA         1
## 1730: MAG655_01347    unk                                 <NA>     NA         1
## 1731: MAG655_01348   GH78          GH78;CBM67     GH78   CBM67     NA         1
##       new_labels
##    1:       susD
##    2:       susC
##    3:         GT
##    4:        unk
##    5:       susD
##   ---           
## 1727:        unk
## 1728:        unk
## 1729:         PL
## 1730:        unk
## 1731:         GH

filtering trSusCD Genes from p.copri MAGs

trSusCD PULs in P. copri (+) vs (-)

filter Prevotellaceae MAGs abundance > 0.1 %

filter Prevotella abundance > 0.1 %

Calculate standard error of the mean
## ------------------------------------------------------------------------------
## You have loaded plyr after dplyr - this is likely to cause problems.
## If you need functions from both plyr and dplyr, please load plyr first, then dplyr:
## library(plyr); library(dplyr)
## ------------------------------------------------------------------------------
## 
## Attaching package: 'plyr'
## The following object is masked from 'package:purrr':
## 
##     compact
## The following objects are masked from 'package:dplyr':
## 
##     arrange, count, desc, failwith, id, mutate, rename, summarise,
##     summarize
## The following object is masked from 'package:here':
## 
##     here
## The following object is masked from 'package:maps':
## 
##     ozone

Barplot with SE

## Warning: `expand_scale()` is deprecated; use `expansion()` instead.

P. copri MAGS abundance and diet associations

filter Prevotellaceae MAGs abundance > 0.1 %
LS0tCnRpdGxlOiAiRGl2ZXJzaXR5IGFuYWx5c2lzIG9mIFAuIGNvcHJpIE1BR3MgaW4gZGlzdGluY3QgZGlldGFyeSBoYWJpdHMiCmF1dGhvcjogIkVyaWMgSi5DLiBHYWx2ZXoiCmRhdGU6ICI5LzYvMjAxOSIKb3V0cHV0OiAKICBodG1sX2RvY3VtZW50OiAKICAgIGhpZ2hsaWdodDogcHlnbWVudHMKICAgIHRoZW1lOiBmbGF0bHkKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICAgIGdyYXBoaWNzOiB5ZXMKICAgIHRvYzogeWVzCmVkaXRvcl9vcHRpb25zOiAKICBjaHVua19vdXRwdXRfdHlwZTogaW5saW5lCi0tLQpfX0xhc3QgbW9kaWZpY2F0aW9uOl9fIGByIGZvcm1hdChTeXMudGltZSgpLCAnJWQgJUIsICVZJylgCgpARXJpY0pDR2FsdmV6Cgo8IS0tIG1vcmUgLS0+CgoKKipUaGUgZGF0YSByZS1hbmFsaXplZCBpbiB0aGlzIHNlY3Rpb24gaGFzIGJlZW4gcHJldmlvdWxzeSBwdWJsaXNoZWQgaW4gOioqCgpEZSBGaWxpcHBpcywgRi4sIFBhc29sbGksIEUuLCBUZXR0LCBBLiwgVGFyYWxsbywgUy4sIE5hY2NhcmF0aSwgQS4sIERlIEFuZ2VsaXMsIE0uLCBOZXZpYW5pLCBFLiwgQ29jb2xpbiwgTC4sIEdvYmJldHRpLCBNLiwgU2VnYXRhLCBOLiwgZXQgYWwuICgyMDE5KS4gRGlzdGluY3QgR2VuZXRpYyBhbmQgRnVuY3Rpb25hbCBUcmFpdHMgb2YgSHVtYW4gSW50ZXN0aW5hbCBQcmV2b3RlbGxhIGNvcHJpIFN0cmFpbnMgQXJlIEFzc29jaWF0ZWQgd2l0aCBEaWZmZXJlbnQgSGFiaXR1YWwgRGlldHMuIENlbGwgSG9zdCBNaWNyb2JlIDI1LCA0NDQtNDUzLmUzLgoKYGBge3J9CiAgbGlicmFyeSgiZGF0YS50YWJsZSIpCiAgbGlicmFyeSgibWFwdG9vbHMiKQogIGxpYnJhcnkoImdnYWx0IikKICBsaWJyYXJ5KCJnZ3RoZW1lcyIpCiAgbGlicmFyeSgidGliYmxlIikKICBsaWJyYXJ5KCJ2aXJpZGlzIikKICBsaWJyYXJ5KCJtYXBzIikKICBsaWJyYXJ5KCJwaHlsb3NlcSIpCiAgbGlicmFyeSgiaGVyZSIpCiAgbGlicmFyeSgiTUlLSWJpb21lUiIpCgpgYGAKCiMjIERhdGEgTG9hZAoKYGBge3J9Ck1BR3NfdGFibGUgPC0gYXNfdGliYmxlKGZyZWFkKCIuLi9kYXRhL21lZGlhbl9jb3ZlcmFnZV9nZW5vbWVzLnRzdiIsIHNlcCA9ICJcdCIsIGhlYWRlciA9IFQpKSAKTUFHc190YWJsZSRWMSA8LSBnc3ViKHggPSBNQUdzX3RhYmxlJFYxLCBwYXR0ZXJuID0gIi1pbnRlcmxldiIsIHJlcGxhY2VtZW50ID0gIiIpCgpNQUdzX3RheCA8LSBhc190aWJibGUoZnJlYWQoIi4uL2RhdGEvdGF4b25vbXkudHN2Iiwgc2VwID0gIlx0IiwgaGVhZGVyID0gVCkpCm1hcHBfZmlsZSA8LSAgYXNfdGliYmxlKGZyZWFkKCIuLi9kYXRhL0ZpbGlwcGlzX2V0X2FsX2RhdGFfbWV0YWRhdGEudHN2IikpCgp0cmVlX2RhdGEgPC0gcGh5bG9zZXE6OnBoeV90cmVlKHBoeWxvc2VxOjppbXBvcnRfcWlpbWUodHJlZWZpbGVuYW1lID0gIi4uL2RhdGEvdHJlZS5ud2siKSkgCgpsaWJyYXJ5KGRwbHlyKQoKZHBseXI6OnJlbmFtZShkcGx5cjo6Y291bnQobWFwcF9maWxlLCBMb2NhdGlvbiksIEZyZXEgPSBuKQpkcGx5cjo6cmVuYW1lKGRwbHlyOjpjb3VudChtYXBwX2ZpbGUsIERpZXQpLCBGcmVxID0gbikKCmBgYAoKCiMjIEl0YWx5IG1hcApgYGB7ciwgZmlnLndpZHRoPTYsIGZpZy5oZWlnaHQ9Nn0KIyMgbW9kaWZpZWQgZnJvbSBCb2IgUnVkaXMKIyMgaHR0cHM6Ly9zdGF0LmV0aHouY2gvcGlwZXJtYWlsL3ItaGVscC8yMDE2LUp1bmUvNDM5MTIzLmh0bWwKCiMgZ2V0IGl0YWx5IHJlZ2lvbiBtYXAKICBpdGFseV9tYXAgPC0gbWFwX2RhdGEoIml0YWx5IikKCiAgIyB5b3VyIGRhdGEgd2lsbCBuZWVkIHRvIGhhdmUgdGhlc2UgcmVnaW9uIG5hbWVzCiAgcHJpbnQodW5pcXVlKGl0YWx5X21hcCRyZWdpb24pKQoKICAjIHdlJ2xsIHNpbXVsYXRlIHNvbWUgZGF0YSBmb3IgdGhpcwogIHNldC5zZWVkKDE0OTIpCiAgI2Nob3JvX2RhdCA8LSBkYXRhX2ZyYW1lKHJlZ2lvbj11bmlxdWUoaXRhbHlfbWFwJHJlZ2lvbiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgI3ZhbHVlPXNhbXBsZSgxMDAsIGxlbmd0aChyZWdpb24pKSkKICAKc2VsZWN0X3JlZyA8LSBkYXRhLmZyYW1lKHJlZ2lvbj1jKCJCYXJpIiwgIkJvbG9nbmEiLCAiUGFybWEiLCAiVG9yaW5vIiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgbnVtYmVyID0gYygxNiwgNSwgMTgsIDYyKSApCiAgCiAgZ2cgPC0gZ2dwbG90KCkKCiAgIyBsYXkgZG93biB0aGUgYmFzZSBsYXllcgogIGdnIDwtIGdnICsgZ2VvbV9tYXAoZGF0YT1pdGFseV9tYXAsIG1hcD1pdGFseV9tYXAsCiAgICAgICAgICAgICAgICAgICAgICBhZXMobG9uZywgbGF0LCBtYXBfaWQ9cmVnaW9uKSwKICAgICAgICAgICAgICAgICAgICAgIGNvbG9yPSIjYjJiMmIyIiwgc2l6ZT0wLjEsIGZpbGw9IiMyNTI1MjUiKQoKICAjIGZpbGwgaW4gdGhlIHJlZ2lvbnMgd2l0aCB0aGUgZGF0YQogIGdnIDwtIGdnICsgZ2VvbV9tYXAoZGF0YT1zZWxlY3RfcmVnLCBtYXA9aXRhbHlfbWFwLAogICAgICAgICAgICAgICAgICAgICAgYWVzKGZpbGw9YXMuY2hhcmFjdGVyKG51bWJlciksIG1hcF9pZD1yZWdpb24pLAogICAgICAgICAgICAgICAgICAgICAgY29sb3I9IiNiMmIyYjIiLCBzaXplPTAuMSkKCiAgIyBncmVhdCBjb2xvciBwYWxldHRlICh1c2UgYSBiZXR0ZXIgbGVnZW5kIHRpdGxlKQogIGdnIDwtIGdnICsgc2NhbGVfZmlsbF9nZG9jcygiRG9ub3JzICMiKQoKICAjIGRlY2VudCBtYXAgcHJvamVjdGlvbiBmb3IgaXRhbHkgY2hvcm9wbGV0aAogICNnZyA8LSBnZyArIGNvb3JkX3Byb2ooaXRhbHlfcHJvaikKCiAgIyBnb29kIGJhc2UgdGhlbWUgZm9yIG1vc3QgbWFwcwogIGdnIDwtIGdnICsgdGhlbWVfbWFwKCkKCiAgIyBtb3ZlIHRoZSBsZWdlbmQKICBnZyA8LSBnZyAjKyB0aGVtZShsZWdlbmQucG9zaXRpb249YygwLjk1LCAwLjMpKQoKICBnZyAKCmBgYAoKIyMgUHJlcGFyZSBtZXRhZ2Vub21pYyBkYXRhIG91dHB1dHMgZnJvbSBBVExBUyB0byBwaHlsb3NlcQpgYGB7cn0KbWFnc19tYXRyaXggPC0gdChkYXRhLm1hdHJpeChNQUdzX3RhYmxlWywyOm5jb2woTUFHc190YWJsZSldKSkKY29sbmFtZXMobWFnc19tYXRyaXgpIDwtIE1BR3NfdGFibGUkVjEKCm90dW1hZ3MgPC0gb3R1X3RhYmxlKG1hZ3NfbWF0cml4LCB0YXhhX2FyZV9yb3dzID0gVCkKCgp0YXhfbWF0cml4IDwtIGFzLm1hdHJpeChNQUdzX3RheFssMzpuY29sKE1BR3NfdGF4KV0pCnJvdy5uYW1lcyh0YXhfbWF0cml4KSA8LSBNQUdzX3RheCRgIyBiaW5gCgp0YXhtYWdzIDwtIHRheF90YWJsZSh0YXhfbWF0cml4KQoKc2FtcGxlbWFncyA8LSBzYW1wbGVfZGF0YShtYXBwX2ZpbGUpCnJvdy5uYW1lcyhzYW1wbGVtYWdzKSA8LSBtYXBwX2ZpbGUkU2FtcGxlSUQKCmBgYAoKIyMgQ3JlYXRlIHBoeWxvc2VxIG9iamVjdApgYGB7cn0KcGh5bG8gPC0gcGh5bG9zZXEob3R1bWFncywgdGF4bWFncywgc2FtcGxlbWFncywgdHJlZV9kYXRhKQpwaHlfdHJlZShwaHlsbykgPC0gIGFwZTo6cm9vdChwaHlfdHJlZShwaHlsbyksIHNhbXBsZSh0YXhhX25hbWVzKHBoeWxvKSwgMSksIHJlc29sdmUucm9vdCA9IFQpCgoKY29sbmFtZXModGF4X3RhYmxlKHBoeWxvKSkgPC0gYygiUGh5bHVtIiwgIkNsYXNzIiwgIk9yZGVyIiwgIkZhbWlseSIsICJHZW51cyIsICJTcGVjaWVzIikKCiNvdHVfdGFibGUocGh5bG8pW290dV90YWJsZShwaHlsbyk8MTBdIDwtIDAKCmBgYAoKCiMjIGFscGhhIGRpdmVyc2l0eSBieSBEaWV0CmBgYHtyLCAgZmlnLnNob3cgPSAiaG9sZCIsIG91dC53aWR0aCA9ICI1MCUiLCB3YXJuaW5nPUZBTFNFfQojIG1pbl9jb3VudCBpbiB0aGlzIGNhc2UgaXMgMTBYIGNvdmVyYWdlCnBoeWxvIDwtIGFscGhhX2Rpdl9jYWxjKHBoeWxvID0gIHBoeWxvLCBtaW5fY291bnQgPSAxMCkKCmFscGhhX2Rpdl9wbG90cyhwaHlsbywgeF9heGlzID0gIkRpZXQiLCBjb2xvcl92YXIgPSAiRGlldCIpCgpgYGAgCgpgYGB7cn0KIyMgVHJhbnNmb3JtIHRvICglKSByZWxhdGl2ZSBhYnVuZGFjZQoKcGh5bG9fUiA8LSBNSUtJYmlvbWVSOjpjYWxjX3JlbF9hYnVuZChwaHlsbykKYGBgCgojIyBQQ29BIGFuZCBOTURTIGNvbXBvc2l0aW9uIGJ5IERpZXQgYW5kIExvY2F0aW9uIAoKYGBge3J9CiMjIE5NRFMKTUlLSWJpb21lUjo6YmV0YV9vcmRpbmF0aW9uKHBoeWxvX1IsIG9yZGluYXRpb25fdHlwZSA9ICJOTURTIiwgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSAiRGlldCIsIHRhZ3R5cGUgPSBOVUxMLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9ybXVsYSA9IGMoIkRpZXQgKyBMb2NhdGlvbiArIFNSQV9TdHVkeSIpKQoKIyMgTk1EUwpNSUtJYmlvbWVSOjpiZXRhX29yZGluYXRpb24ocGh5bG9fUiwgb3JkaW5hdGlvbl90eXBlID0gIk5NRFMiLCAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9ICJMb2NhdGlvbiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9zdGFyID0gRiwgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvcm11bGEgPSAiIikKCiMjIFBDb0EKCk1JS0liaW9tZVI6OmJldGFfb3JkaW5hdGlvbihwaHlsb19SLCBvcmRpbmF0aW9uX3R5cGUgPSAiUENvQSIsICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gIkxvY2F0aW9uIiwgc2hhcGUgPSAiRGlldCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3N0YXIgPSBGLCAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9ybXVsYSA9ICIiKQoKYGBgCgojIyBCYXJwbG90IChhYnNvbHV0ZSBjb3ZlcmFnZSksIGZhY2V0IGJ5IERpZXQKIyMjIFBoeWx1bSBhbmQgRmFtaWx5CgpgYGB7ciwgZmlnLmhlaWdodD0gNiwgZmlnLndpZHRoPSAxMH0KCk1JS0liaW9tZVI6OmFidW5kYW5jZV9wbG90KHBoeWxvLCAiU2FtcGxlSUQiLCB0YXhsZXYgPSAiT3JkZXIiLCBmYWNldGJ5ID0gIkRpZXQiLCBudGF4YSA9IDEyLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgb3JkZXJiYXIgPSAiQkZfcmF0aW8iICkgKwogIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfYmxhbmsoKSkKCk1JS0liaW9tZVI6OmFidW5kYW5jZV9wbG90KHBoeWxvLCAiU2FtcGxlSUQiLCB0YXhsZXYgPSAiRmFtaWx5IiwgZmFjZXRieSA9ICJEaWV0IiwgbnRheGEgPSAxMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgb3JkZXJiYXIgPSAiQkZfcmF0aW8iICkgKwogIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfYmxhbmsoKSkKYGBgCgojIyBCYXJwbG90IHJlbGF0aXZlIGFidW5kYW5jZSAoJSksIGZhY2V0IGJ5IERpZXQKIyMjIyBQaHlsdW0gYW5kIEZhbWlseQoKYGBge3IsIGZpZy5oZWlnaHQ9IDYsIGZpZy53aWR0aD0gMTB9CgpNSUtJYmlvbWVSOjphYnVuZGFuY2VfcGxvdChwaHlsb19SLCAiU2FtcGxlSUQiLCB0YXhsZXYgPSAiUGh5bHVtIiwgZmFjZXRieSA9ICJEaWV0IiwgbnRheGEgPSAxMiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIG9yZGVyYmFyID0gIkJGX3JhdGlvIiApICsKICAgIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfYmxhbmsoKSkKCk1JS0liaW9tZVI6OmFidW5kYW5jZV9wbG90KHBoeWxvX1IsICJTYW1wbGVJRCIsIHRheGxldiA9ICJGYW1pbHkiLCBmYWNldGJ5ID0gIkRpZXQiLCBudGF4YSA9IDEyLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgb3JkZXJiYXIgPSAiQkZfcmF0aW8iICkgKwogICAgdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF9ibGFuaygpKQoKYGBgCgoKIyMgQWJ1bmRhbmNlIG9mIFByZXZvdGVsbGFjZWFlIE1BR3MgYnkgZGlldAojIyMjIFRvdGFsIHJlY29udHJ1Y3RlZCBNQUdzIDM0CgojIyMjIFN1YnNldGluZyAgUHJldm90ZWxsYWNlYWUgTUFHcyBhbmQgYXJyZW5nZWQgYnkgYWJ1bmRhbmNlCmBgYHtyLCBmaWcuaGVpZ2h0PSA2LCBmaWcud2lkdGg9IDEwfQoKcGh5bG9fcHJldm8gPC0gc3Vic2V0X3RheGEocGh5c2VxID0gcGh5bG9fUiwgRmFtaWx5ID09ICJQcmV2b3RlbGxhY2VhZSIpCgoKbXlkYXRhX3JlbF9nbG9tX2F2ZXIucHNxIDwtIHBydW5lX3RheGEobmFtZXMoc29ydCh0YXhhX3N1bXMocGh5bG9fcHJldm8pLCBUKSlbMTozNV0sIHBoeWxvX3ByZXZvKQpteWRhdGFfcmVsX2F2ZXJhZ2UubWVsdCA8LSBwc21lbHQobXlkYXRhX3JlbF9nbG9tX2F2ZXIucHNxKQoKcCA8LSBnZ3Bsb3QobXlkYXRhX3JlbF9hdmVyYWdlLm1lbHRbb3JkZXIobXlkYXRhX3JlbF9hdmVyYWdlLm1lbHQkT3JkZXIsIGRlY3JlYXNpbmcgPSBUKSxdLCBhZXMocmVvcmRlcihTYW1wbGUsIEFidW5kYW5jZSksIHk9QWJ1bmRhbmNlLCBmaWxsPU9UVSkpCnAgPC0gcCArIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IikKcCArIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMC45KSkgKyB5bGFiKCJNQUdzIG1lYW4gY292ZXJhZ2UgKCUpIikgKwogIGZhY2V0X3dyYXAofkRpZXQsICBzY2FsZXMgPSAiZnJlZV94IiwgIGxhYmVsbGVyID0gbGFiZWxfd3JhcF9nZW4obXVsdGlfbGluZT1GQUxTRSkpICsgCiAgI3NjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiUGFpcmVkIikgKyB4bGFiKCJEb25vciMiKSArIAogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpKSArCiAgZ2dwbG90Mjo6c2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gZ2dwdWJyOjpnZXRfcGFsZXR0ZShwYWxldHRlID0gInNpbXBzb25zIiwgCiAgICAgICAgayA9IDM0KSkgKwogIHhsYWIoIkRvbm9yX0lkIikgKyAKICAgIGdncGxvdDI6OnNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKDAsIDgwKSwgZXhwYW5kPWdncGxvdDI6OmV4cGFuZF9zY2FsZShtdWx0ID0gMC4wMDEsIGFkZCA9MCkpICsgCiAgICBnZ3Bsb3QyOjpzY2FsZV94X2Rpc2NyZXRlKGV4cGFuZD1jKDAuMDUsIDApKSArCiAgICAgICAgIyAgeWxpbSgwLDcwKSArCiAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwYW5lbC5ncmlkLm1ham9yLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgIHBhbmVsLmdyaWQubWlub3IueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgcGFuZWwuZ3JpZC5tYWpvci54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICBwYW5lbC5ncmlkLm1pbm9yLnggPSBlbGVtZW50X2JsYW5rKCkpCgoKYGBgCgojIyBQLiBjb3ByaSBNQUdzOiAKIyMjIyBNQUc2MDkgaXMgaGlnaGx5IGFidW5kYW50IGFuZCBwcmVkb21pbmF0ZXMgaW4gVmVnYW5zIAoKYGBge3IsIGZpZy5oZWlnaHQ9IDYsIGZpZy53aWR0aD0gMTB9CgpwY29wcmkgPC0gYygiTUFHNjA5IiwKICAgICAgICAgICJNQUc2MTAiLAogICAgICAgICAgIk1BRzYxMSIsCiAgICAgICAgICAiTUFHNjEyIiwKICAgICAgICAgICJNQUc2MTMiKQoKcGNvcHJpX2NvbCA8LSBjKCJNQUc2MDkiID0iI2UzMWExYyIsCiAgICAgICAgICAiTUFHNjEwIj0iIzIzOGI0NSIsCiAgICAgICAgICAiTUFHNjExIj0iIzc0YzQ3NiIsCiAgICAgICAgICAiTUFHNjEyIj0iI2Q5ZjBhMyIsCiAgICAgICAgICAiTUFHNjEzIj0iIzFmNzhiNCIpCgpwaHlsb19wcmV2byA8LSBzdWJzZXRfdGF4YShwaHlzZXEgPSBwaHlsb19SLCBwaHlsb3NlcTo6dGF4YV9uYW1lcyhwaHlsb19SKSAlaW4lIHBjb3ByaSkKCm15ZGF0YV9yZWxfZ2xvbV9hdmVyLnBzcSA8LSBwcnVuZV90YXhhKG5hbWVzKHNvcnQodGF4YV9zdW1zKHBoeWxvX3ByZXZvKSwgVCkpWzE6MTJdLCBwaHlsb19wcmV2bykKbXlkYXRhX3JlbF9hdmVyYWdlLm1lbHQgPC0gcHNtZWx0KG15ZGF0YV9yZWxfZ2xvbV9hdmVyLnBzcSkKCm15ZGF0YV9yZWxfYXZlcmFnZS5tZWx0JERpZXQgPC0gZmFjdG9yKG15ZGF0YV9yZWxfYXZlcmFnZS5tZWx0JERpZXQsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJPbW5pdm9yZSIsICJWZWdldGFyaWFuIiwgIlZlZ2FuIikpCgpwIDwtIGdncGxvdChteWRhdGFfcmVsX2F2ZXJhZ2UubWVsdFtvcmRlcihteWRhdGFfcmVsX2F2ZXJhZ2UubWVsdCRPcmRlciwgZGVjcmVhc2luZyA9IFQpLF0sIGFlcyhyZW9yZGVyKFNhbXBsZSwgQWJ1bmRhbmNlKSwgeT1BYnVuZGFuY2UsIGZpbGw9T1RVKSkKcCA8LSBwICsgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiKQpwZiA8LSBwICsgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAwLjkpKSArIHlsYWIoIk1BR3MgbWVhbiBjb3ZlcmFnZSAoJSkiKSArCiAgZmFjZXRfd3JhcCh+RGlldCwgIHNjYWxlcyA9ICJmcmVlX3giLCBuY29sID0gNCwgbGFiZWxsZXIgPSBsYWJlbF93cmFwX2dlbihtdWx0aV9saW5lPUZBTFNFKSkgKyAKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IHBjb3ByaV9jb2wpICsgeGxhYigiRG9ub3JfSWQiKSArIAogICAgZ2dwbG90Mjo6c2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoMCwgODApLCBleHBhbmQ9Z2dwbG90Mjo6ZXhwYW5kX3NjYWxlKG11bHQgPSAwLjAwMSwgYWRkID0wKSkgKyAKICAgIGdncGxvdDI6OnNjYWxlX3hfZGlzY3JldGUoZXhwYW5kPWMoMC4wNSwgMCkpICsKICAgICAgICAjICB5bGltKDAsNzApICsKICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBhbmVsLmdyaWQubWFqb3IueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgcGFuZWwuZ3JpZC5taW5vci55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICBwYW5lbC5ncmlkLm1ham9yLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgIHBhbmVsLmdyaWQubWlub3IueCA9IGVsZW1lbnRfYmxhbmsoKSkKCnBmCgojZXhwb3J0IDV4NwoKYGBgCgoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMjICBQVUxzIGRpYWdyYW0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKCgpgYGB7cn0KbGlicmFyeSgiZGF0YS50YWJsZSIpCmxpYnJhcnkoInB1cnJyIikKCnRibF9mcmVhZCA8LSAKICAgIGxpc3QuZmlsZXMocGF0aCA9ICIuLi9kYXRhL3ByZWRpY3RlZF9QVUxzX2luX3BNQUdzLyIsIGZ1bGwubmFtZXMgPSBULCBwYXR0ZXJuID0gIioucHVscy50c3YiKSAlPiUgCiAgICBtYXBfZGYofmZyZWFkKC4pKQoKCnB1bHNfZ2VuZXNfc2VwIDwtIHRibF9mcmVhZCAlPiUgdGlkeXI6OnNlcGFyYXRlKGhtbSwgYygiQ2F6eV9GYW0iLCJzdWJfZmFtIiksIHNlcCA9ICIoW1xcX1xcO10pIiwgcmVtb3ZlID0gRikKCgojIyBjaGVjayBmb3IgZHVwbGljYXRlcyAoZm9yciBnZ2VuZXMgY2FuIG5vdCBiZSBhbGlnbmVkIHdpdGggZHVwbGljYXRlIG5hbWVzKQojICBwdWxzX2dlbmVzX3NlcFshZHVwbGljYXRlZChwdWxzX2dlbmVzX3NlcFssYygicHVsaWQiLCJzdXMiKV0sZnJvbUxhc3Q9RkFMU0UpLF0KCiMjIGFkZCBhIG51bWJlciB0byBzdXNDIHRoYXQgaXMgdGhlIGFsaWduaW5nIGdlbmUgaW4gdGhpcyBjYXNlIGFuZCBjcmVhdGUgYSBuZXcgY29sdW1uCmRmX2ZpcnN0X3N1cyA8LSBwdWxzX2dlbmVzX3NlcFshZHVwbGljYXRlZChwdWxzX2dlbmVzX3NlcFssYygicHVsaWQiLCJzdXMiKV0sZnJvbUxhc3Q9RkFMU0UpLF0gJT4lCiAgICAgICAgICAgICAgICBtdXRhdGUoLiwgZmlyc3Rfc3VzID0gaWZlbHNlKHB1bHNfZ2VuZXNfc2VwWyFkdXBsaWNhdGVkKHB1bHNfZ2VuZXNfc2VwWywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYygicHVsaWQiLCJzdXMiKV0sIGZyb21MYXN0PUZBTFNFKSxdJHN1cz09ICJzdXNDIiwgInN1c0NfMSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIm5vbmUiKQogICAgICAgICAgICAgICAgICAgICAgICkKCiNFZGl0IGFuZCBjb21iaW5lIENhenltZXMgYW5kIFN1cyBnZW5lcwpwdWxzX2dlbmVzX3NlcCRzdXMgPC0gaWZlbHNlKHB1bHNfZ2VuZXNfc2VwJHByb3RlaW5faWQgJWluJSAoZmlsdGVyKGRmX2ZpcnN0X3N1cywgZmlyc3Rfc3VzID09InN1c0NfMSIpICU+JSAgICAgICAgICAgICAgICAgICAgIHNlbGVjdChwcm90ZWluX2lkKSAlPiUgcHVsbCgpKSwgInN1c0NfMSIsIHB1bHNfZ2VuZXNfc2VwW1sic3VzIl1dKQojIyBjb21iaW5pbmcgc3RlcApwdWxzX2dlbmVzX3NlcCRzdXMgPC0gaWZlbHNlKHB1bHNfZ2VuZXNfc2VwJHN1cz09IiIsIHB1bHNfZ2VuZXNfc2VwW1siQ2F6eV9GYW0iXV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHVsc19nZW5lc19zZXBbWyJzdXMiXV0pCgpwdWxzX2dlbmVzX3NlcCRzdXMgPC0gaWZlbHNlKHB1bHNfZ2VuZXNfc2VwJHN1cz09IiIsICJ1bmsiLCBwdWxzX2dlbmVzX3NlcFtbInN1cyJdXSkKI2NvbnZlcmluZyB0aGUgc3RyYW5kcyB0byBudW1lcmljIC0+IGlkZWFsbHkgZm9yIGFycm93cyBkaXJlY3Rpb24sIFdJUApwdWxzX2dlbmVzX3NlcCRkaXJlY3Rpb24gPC0gaWZlbHNlKHB1bHNfZ2VuZXNfc2VwJHN0cmFuZCA9PSAiKyIsIDEsIC0xKQpwdWxzX2dlbmVzX3NlcCRuZXdfbGFiZWxzIDwtIGdzdWIoJ1swLTldKycsICcnLCBwdWxzX2dlbmVzX3NlcCRzdXMpICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdzdWIoJ18nLCAnJywgLikKCnB1bHNfZ2VuZXNfc2VwCgpgYGAKCgojIyBmaWx0ZXJpbmcgdHJTdXNDRCBHZW5lcyBmcm9tIHAuY29wcmkgTUFHcwpgYGB7cn0KdHJQVUxfcHVsc19zZXAgPC0gcHVsc19nZW5lc19zZXAgJT4lCiAgICBkcGx5cjo6ZmlsdGVyKC4sIGdlbm9tZSA9PSAiTUFHNjA5IiAmIHB1bGlkID09IGMoIlBVTDQiKSB8CiAgICAgICAgICAgICAgICAgICAgIGdlbm9tZSA9PSAiTUFHNjA5IiAmIHB1bGlkID09IGMoIlBVTDYiKSB8CiAgICAgICAgICAgICAgICAgICAgIGdlbm9tZSA9PSAiTUFHNjEwIiAmIHB1bGlkID09IGMoIlBVTDEwIikgfAogICAgICAgICAgICAgICAgICAgICBnZW5vbWUgPT0gIk1BRzYxMSIgJiBwdWxpZCA9PSBjKCJQVUwyIikgfAogICAgICAgICAgICAgICAgICAgICBnZW5vbWUgPT0gIk1BRzYxMSIgJiBwdWxpZCA9PSBjKCJQVUw0IikKICAgICAgICAgICAgICAgICAgICAgKSAlPiUKICB0aWR5cjo6dW5pdGUoInB1bGlkX3VucSIsIGdlbm9tZTpwdWxpZCwgc2VwPSJfIiwgcmVtb3ZlPUYpCgoKYGBgCgoKIyMjIyBQVUxzIHBsb3QKCmBgYHtyLCBmaWcuaGVpZ2h0PSA2LCBmaWcud2lkdGg9IDEwfQpsaWJyYXJ5KGdnZ2VuZXMpCgpQVUxzX2NvbCA8LSBjKCJzdXNDIiA9ICIjNmE1MWEzIiwKICAgICAgICAgICAgICAic3VzRCIgPSAiI2ZkOGQzYyIsCiAgICAgICAgICAgICAgIkdIMiIgPSAiI2UwZjNkYiIsIAogICAgICAgICAgICAgICJHSDUiID0gIiNjY2ViYzUiLAogICAgICAgICAgICAgICJHSDEwIiA9ICIjYThkZGI1IiwKICAgICAgICAgICAgICAiR0gxMyIgPSAiIzdiY2NjNCIsCiAgICAgICAgICAgICAgIkdINDMiID0gIiM0ZWIzZDMiLAogICAgICAgICAgICAgICJHSDk3IiA9ICIjMmI4Y2JlIiwKICAgICAgICAgICAgICAiR0gxMDUiID0gIiMwODY4YWMiLAogICAgICAgICAgICAgICJQTDExIiA9ICIjZjRhNTgyIiwgCiAgICAgICAgICAgICAgInVuayIgPSAiI2UwZTBlMCIgIAogICAgICAgICAgICAgICkKICAgICAKZmFjdG9yKHRyUFVMX3B1bHNfc2VwJHN1cykKCgpnZ3Bsb3QoCiAgdHJQVUxfcHVsc19zZXAsCiAgYWVzKHhtaW4gPSBzdGFydCwgeG1heCA9IGVuZCwgeSA9IHB1bGlkX3VucSwgZmlsbCA9IHN1cywgZm9yd2FyZCA9IGRpcmVjdGlvbiwgbGFiZWwgPSBzdXMpKSArCiAgZ2VvbV9nZW5lX2Fycm93KGFycm93X2JvZHlfaGVpZ2h0ID0gZ3JpZDo6dW5pdCg0LCAibW0iKSwgYXJyb3doZWFkX2hlaWdodCA9IHVuaXQoNCwgIm1tIiksIAogICAgICAgICAgICAgICAgICBhcnJvd2hlYWRfd2lkdGggPSB1bml0KDIsICJtbSIpKSArCiAgZ2VvbV9nZW5lX2xhYmVsKGFsaWduID0gImNlbnRyZSIpICsKICBmYWNldF93cmFwKH4gcHVsaWRfdW5xLCBzY2FsZXMgPSAiZnJlZSIsIG5jb2wgPSAxKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gUFVMc19jb2wsIGJyZWFrcz1jKCJzdXNDIiwgInN1c0QiLCAiR0gyIiwgIkdINSIsICJHSDEwIiwgIkdIMTMiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkdINDMiLCAiR0g5NyIsICJHSDEwNSIsICJQTDExIiwgInVuayIpKSArCiAgeWxhYigiIikgKwogIHhsYWIoIkxvY3VzIGxlbmd0aCAoYnApIikgKwogIHRoZW1lX2dlbmVzKCkKYGBgCgojIyB0clN1c0NEIFBVTHMgaW4gUC4gY29wcmkgKCspIHZzICgtKQojIyMjIGZpbHRlciBQcmV2b3RlbGxhY2VhZSBNQUdzIGFidW5kYW5jZSA+IDAuMSAlCgojIyBmaWx0ZXIgUHJldm90ZWxsYSBhYnVuZGFuY2UgPiAwLjEgJQoKYGBge3J9CnRyUFVMIDwtIGMoIk1BRzYwOSIsICJNQUc2MTAiLCAiTUFHNjExIikgCgpwdWxzX2RhdGEgPC0gbXlkYXRhX3JlbF9hdmVyYWdlLm1lbHQgJT4lCiAgZHBseXI6Om11dGF0ZSguLCBQVUwgPSBpZmVsc2UoT1RVICVpbiUgdHJQVUwsICJ0clBVTCgrKSIsICJ0clBVTCgtKSIpKSAlPiUKICBmaWx0ZXIoLiwgQWJ1bmRhbmNlID4gMC4xKQpgYGAKCgpgYGB7cn0KICAjIyBzdW1tYXJpemluZyBhbmQgZ2V0dGluZyB0aGUgbWVhbiBhYnVuZGFuY2UgYnkgdHJQVUwKICBzdW1fbWVsdGVkX2FidW5kIDwtIHB1bHNfZGF0YSAlPiUgCiAgICAgICAgICAgICAgICAgZHBseXI6Omdyb3VwX2J5KFNhbXBsZSwgRGlldCwgUFVMKSAlPiUKICAgICAgICAgICAgICAgICBkcGx5cjo6c3VtbWFyaXNlKHN1bV9BYnVuZGFuY2UgPSBzdW0oQWJ1bmRhbmNlKSkKCgpwIDwtIHN1bV9tZWx0ZWRfYWJ1bmQgJT4lCiAgZ2dwbG90KC4sIGFlcyh4ID0gUFVMLCB5ID0gc3VtX0FidW5kYW5jZSksIGNvbG9yID0gU2FtcGxlKSArIAogIGdlb21fYm94cGxvdCgpICsKICBnZW9tX2ppdHRlcihhZXMoYWxwaGE9MC43KSwgd2lkdGggPSAwLjI1KQpwIDwtIHAgKyB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDAuOSkpICsgeWxhYigiTUFHcyBtZWFuIGNvdmVyYWdlICglKSIpICsKICAgIGZhY2V0X3dyYXAofkRpZXQsICBzY2FsZXMgPSAiZnJlZV94IiwgbmNvbCA9IDQsIGxhYmVsbGVyID0gbGFiZWxfd3JhcF9nZW4obXVsdGlfbGluZT1GQUxTRSkpICsgCiAgICAjc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHBjb3ByaV9jb2wpICsgeGxhYigiRG9ub3JfSWQiKSArIAogICAgIyBnZ3Bsb3QyOjpzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygwLCA4MCksIGV4cGFuZD1nZ3Bsb3QyOjpleHBhbmRfc2NhbGUobXVsdCA9IDAuMDAxLCBhZGQgPTApKSArIAogICAjIGdncGxvdDI6OnNjYWxlX3hfZGlzY3JldGUoZXhwYW5kPWMoMC4wNSwgMCkpICsKICAgICAgICAjICB5bGltKDAsNzApICsKICAgIHRoZW1lKHBhbmVsLmdyaWQubWFqb3IueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgcGFuZWwuZ3JpZC5taW5vci55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICBwYW5lbC5ncmlkLm1ham9yLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgIHBhbmVsLmdyaWQubWlub3IueCA9IGVsZW1lbnRfYmxhbmsoKSkKCgpteV9jb21wIDwtIGxpc3QoYygidHJQVUwoKykiLCAidHJQVUwoLSkiKSkKcCArIGdncHVicjo6c3RhdF9jb21wYXJlX21lYW5zKGNvbXBhcmlzb25zID0gbXlfY29tcCwgbWV0aG9kID0gInQudGVzdCIpIAoKYGBgCgojIyMjIyBDYWxjdWxhdGUgc3RhbmRhcmQgZXJyb3Igb2YgdGhlIG1lYW4KYGBge3J9CgojIyMjIyMjIyMjIyMjIyMjIyMjZnVuY3Rpb24gb2Ygc3VtbWFyeSBTRQojIyMjIyMjIyMjIyMjIGh0dHA6Ly93d3cuY29va2Jvb2stci5jb20vR3JhcGhzL1Bsb3R0aW5nX21lYW5zX2FuZF9lcnJvcl9iYXJzXyhnZ3Bsb3QyKQoKbGlicmFyeSgicGx5ciIpCgpzdW1tYXJ5U0UgPC0gZnVuY3Rpb24oZGF0YT1OVUxMLCBtZWFzdXJldmFyLCBncm91cHZhcnM9TlVMTCwgbmEucm09RkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICBjb25mLmludGVydmFsPS45NSwgLmRyb3A9VFJVRSkgewogIAogICMgTmV3IHZlcnNpb24gb2YgbGVuZ3RoIHdoaWNoIGNhbiBoYW5kbGUgTkEnczogaWYgbmEucm09PVQsIGRvbid0IGNvdW50IHRoZW0KICBsZW5ndGgyIDwtIGZ1bmN0aW9uICh4LCBuYS5ybT1GQUxTRSkgewogICAgaWYgKG5hLnJtKSBzdW0oIWlzLm5hKHgpKQogICAgZWxzZSAgICAgICBsZW5ndGgoeCkKICB9CiAgCiAgIyBUaGlzIGRvZXMgdGhlIHN1bW1hcnkuIEZvciBlYWNoIGdyb3VwJ3MgZGF0YSBmcmFtZSwgcmV0dXJuIGEgdmVjdG9yIHdpdGgKICAjIE4sIG1lYW4sIGFuZCBzZAogIGRhdGFjIDwtIGRkcGx5KGRhdGEsIGdyb3VwdmFycywgLmRyb3A9LmRyb3AsCiAgICAgICAgICAgICAgICAgLmZ1biA9IGZ1bmN0aW9uKHh4LCBjb2wpIHsKICAgICAgICAgICAgICAgICAgIGMoTiAgICA9IGxlbmd0aDIoeHhbW2NvbF1dLCBuYS5ybT1uYS5ybSksCiAgICAgICAgICAgICAgICAgICAgIG1lYW4gPSBtZWFuICAgKHh4W1tjb2xdXSwgbmEucm09bmEucm0pLAogICAgICAgICAgICAgICAgICAgICBzZCAgID0gc2QgICAgICh4eFtbY29sXV0sIG5hLnJtPW5hLnJtKQogICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgIH0sCiAgICAgICAgICAgICAgICAgbWVhc3VyZXZhcgogICkKICAKICAjIFJlbmFtZSB0aGUgIm1lYW4iIGNvbHVtbiAgICAKICBkYXRhYyA8LSBwbHlyOjpyZW5hbWUoZGF0YWMsIGMoIm1lYW4iID0gbWVhc3VyZXZhcikpCiAgCiAgZGF0YWMkc2UgPC0gZGF0YWMkc2QgLyBzcXJ0KGRhdGFjJE4pICAjIENhbGN1bGF0ZSBzdGFuZGFyZCBlcnJvciBvZiB0aGUgbWVhbgogIAogICMgQ29uZmlkZW5jZSBpbnRlcnZhbCBtdWx0aXBsaWVyIGZvciBzdGFuZGFyZCBlcnJvcgogICMgQ2FsY3VsYXRlIHQtc3RhdGlzdGljIGZvciBjb25maWRlbmNlIGludGVydmFsOiAKICAjIGUuZy4sIGlmIGNvbmYuaW50ZXJ2YWwgaXMgLjk1LCB1c2UgLjk3NSAoYWJvdmUvYmVsb3cpLCBhbmQgdXNlIGRmPU4tMQogIGNpTXVsdCA8LSBxdChjb25mLmludGVydmFsLzIgKyAuNSwgZGF0YWMkTi0xKQogIGRhdGFjJGNpIDwtIGRhdGFjJHNlICogY2lNdWx0CgogIHJldHVybihkYXRhYykKfQoKYGBgCgoKIyMgQmFycGxvdCB3aXRoIFNFCgpgYGB7cn0KCm15X2NvbHNfcGFsIDwtYygidHJQVUwoKykiID0gIiM1MjUyNTIiLCAidHJQVUwoLSkiID0iI2YwZjBmMCIpIAoKcHVsX3N0YXRzIDwtIHN1bW1hcnlTRShkYXRhID0gc3VtX21lbHRlZF9hYnVuZCwgbWVhc3VyZXZhciA9ICJzdW1fQWJ1bmRhbmNlIiwKICAgICAgICAgIGdyb3VwdmFycz1jKCJEaWV0IiwgIlBVTCIpLAogICAgICAgICAgbmEucm09VCwgY29uZi5pbnRlcnZhbD0uOTUsIC5kcm9wPVRSVUUpCgpwIDwtIGdncGxvdChwdWxfc3RhdHMsIGFlcyh4PVBVTCwgeT1zdW1fQWJ1bmRhbmNlLCAgZmlsbD1QVUwpKSArIAogICAgICBnZW9tX2NvbChwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKDEpLCBjb2xvdXI9ImJsYWNrIikgKwogICAgICBmYWNldF9ncmlkKH5EaWV0KSArCiAgICAgIGdncGxvdDI6Omdlb21fZXJyb3JiYXIoZ2dwbG90Mjo6YWVzKHltaW49c3VtX0FidW5kYW5jZSAtIHNlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWF4PXN1bV9BYnVuZGFuY2UgKyBzZSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdpZHRoPS4zLCBhbHBoYT0uNywgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSgwLjgpKSArCiAgICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IG15X2NvbHNfcGFsKSArIAogICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gImJsYWNrIikgKyAKICAgICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxLCBzaXplID0gMjApLAogICAgICAgICAgICAgICAgICBsZWdlbmQudGV4dD1lbGVtZW50X3RleHQoc2l6ZSA9IDE4KSwKICAgICAgICAgICAgICAgICAgc3RyaXAudGV4dC54ID0oZWxlbWVudF90ZXh0KHNpemUgPSAyMCkpLAogICAgICAgICAgICAgICAgICBheGlzLnRleHQueSA9KGVsZW1lbnRfdGV4dChzaXplID0gMjApKSkgKwogICAgICB5bGFiKCJNQUdzIG1lYW4gY292ZXJhZ2UgKCUpIikgKwogICAgICB4bGFiKCIiKSArCiAgICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSwgc2l6ZSA9IDIwKSwKICAgICAgICAgICAgICAgICAgc3RyaXAudGV4dC54ID0oZWxlbWVudF90ZXh0KHNpemUgPSAyMCkpLAogICAgICAgICAgICAgICAgICBheGlzLnRleHQueSA9KGVsZW1lbnRfdGV4dChzaXplID0gMjApKSkgKwogICAgICAgICAgICAgICAgICBnZ3Bsb3QyOjpzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygwLCAyNSksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXhwYW5kPWdncGxvdDI6OmV4cGFuZF9zY2FsZShtdWx0ID0gMC4wMDEsIGFkZCA9MCkpIAoKICAgICAgICAgICAgCnAgKyB0aGVtZV9iYXNlKCkgKyB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDAuOSksCiAgICAgICAgIHBhbmVsLmdyaWQubWFqb3IueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgcGFuZWwuZ3JpZC5taW5vci55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICBwYW5lbC5ncmlkLm1ham9yLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgIHBhbmVsLmdyaWQubWlub3IueCA9IGVsZW1lbnRfYmxhbmsoKSkKCmBgYAoKCiMjIFAuIGNvcHJpIE1BR1MgYWJ1bmRhbmNlIGFuZCBkaWV0IGFzc29jaWF0aW9ucwojIyMjIyBmaWx0ZXIgUHJldm90ZWxsYWNlYWUgTUFHcyBhYnVuZGFuY2UgPiAwLjEgJQoKYGBge3J9CnB1bHNfZGF0YSA8LSBteWRhdGFfcmVsX2F2ZXJhZ2UubWVsdCAlPiUKICBmaWx0ZXIoLiwgQWJ1bmRhbmNlID4gMC4xKQpgYGAKCgojIyMjIHN0YXRzIFBVTHMKYGBge3IsIGZpZy5oZWlnaHQ9IDYsIGZpZy53aWR0aD0gOH0KcCA8LSBnZ3Bsb3QocHVsc19kYXRhLCBhZXMoeCA9IERpZXQsIHkgPSBBYnVuZGFuY2UpLCBjb2xvciA9IE9UVSkKcCA8LSBwICsgZ2VvbV9ib3hwbG90KCkgKyBnZW9tX2ppdHRlcihhZXMoY29sb3I9T1RVLCBhbHBoYT0wLjUpLCB3aWR0aCA9IDAuMjUpCnBmIDwtIHAgKyB5bGFiKCJNQUdzIG1lYW4gY292ZXJhZ2UgKCUpIikgKwogICAgZmFjZXRfd3JhcCh+T1RVLCAgc2NhbGVzID0gImZyZWUiLCBuY29sID0zLCBsYWJlbGxlciA9IGxhYmVsX3dyYXBfZ2VuKG11bHRpX2xpbmU9RkFMU0UpKSArIAogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHBjb3ByaV9jb2wpICsgCiAgICBzY2FsZV94X2Rpc2NyZXRlKGxpbWl0ID0gYygiT21uaXZvcmUiLCAiVmVnZXRhcmlhbiIsICJWZWdhbiIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIk8iLCAiViIsICJWRyIpKSArCiAgICBnZ3Bsb3QyOjpzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygwLCBOQSksIGV4cGFuZD1nZ3Bsb3QyOjpleHBhbmRfc2NhbGUobXVsdCA9IDAuMSwgYWRkID0wLjUpKSArIAogICAjIGdncGxvdDI6OnNjYWxlX3hfZGlzY3JldGUoZXhwYW5kPWMoMC4wNSwgMCkpICsKICAgICAgICAjICB5bGltKDAsNzApICsKICAgIHRoZW1lKHBhbmVsLmdyaWQubWFqb3IueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgcGFuZWwuZ3JpZC5taW5vci55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICBwYW5lbC5ncmlkLm1ham9yLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgIHBhbmVsLmdyaWQubWlub3IueCA9IGVsZW1lbnRfYmxhbmsoKSkKCgojbXlfY29tcCA8LSBsaXN0KGMoIk1BRzYwOSIsIk1BRzYxMCIpLCBjKCJNQUc2MDkiLCJNQUc2MTEiKSwgYygiTUFHNjA5IiwiTUFHNjEyIiksIGMoIk1BRzYwOSIsIk1BRzYxMyIpKQpteV9jb21wIDwtIGxpc3QoYygiT21uaXZvcmUiLCJWZWdldGFyaWFuIiksIGMoIlZlZ2V0YXJpYW4iLCAiVmVnYW4iKSwgYygiT21uaXZvcmUiLCJWZWdhbiIpKQoKcGYgKyBnZ3B1YnI6OnN0YXRfY29tcGFyZV9tZWFucyhjb21wYXJpc29ucyA9IG15X2NvbXAsIGxhYmVsID0gInAuc2lnbmlmIiwgbWV0aG9kID0gIndpbGNveC50ZXN0IikgCgogIHBmICsgZ2dwdWJyOjpzdGF0X2NvbXBhcmVfbWVhbnMoY29tcGFyaXNvbnMgPSBteV9jb21wLCBtZXRob2QgPSAid2lsY294LnRlc3QiKSAKCiNzYXZlIGFzIDZ4NQoKYGBgCg==